home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / Class1Recv.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  16KB  |  548 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/Class1Recv.c++,v 1.45 1994/04/07 21:53:22 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25.  
  26. /*
  27.  * EIA/TIA-578 (Class 1) Modem Driver.
  28.  *
  29.  * Receive protocol.
  30.  */
  31. #include <stdio.h>
  32. #include "Class1.h"
  33. #include "ModemConfig.h"
  34. #include "HDLCFrame.h"
  35. #include "StackBuffer.h"        // XXX
  36.  
  37. #include "t.30.h"
  38. #include <stdlib.h>
  39. #include <time.h>
  40.  
  41. /*
  42.  * Tell the modem to answer the phone.  We override
  43.  * this method so that we can force the terminal's
  44.  * flow control state to be setup to our liking.
  45.  */
  46. CallType
  47. Class1Modem::answerCall(AnswerType type, fxStr& emsg)
  48. {
  49.     if (flowControl == FLOW_XONXOFF)
  50.     setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_FLUSH);
  51.     return FaxModem::answerCall(type, emsg);
  52. }
  53.  
  54. /*
  55.  * Process an answer response from the modem.
  56.  * Since some Class 1 modems do not give a connect
  57.  * message that distinguishes between DATA and FAX,
  58.  * we override the default handling of "CONNECT"
  59.  * message here to force the high level code to
  60.  * probe further.
  61.  */
  62. const AnswerMsg*
  63. Class1Modem::findAnswer(const char* s)
  64. {
  65.     static const AnswerMsg answer = {
  66.     "CONNECT", 7,
  67.     FaxModem::AT_NOTHING, FaxModem::OK, FaxModem::CALLTYPE_UNKNOWN
  68.     };
  69.     return strneq(s, answer.msg, answer.len) ?
  70.     &answer : FaxModem::findAnswer(s);
  71. }
  72.  
  73. /*
  74.  * Begin the receive protocol.
  75.  */
  76. fxBool
  77. Class1Modem::recvBegin(fxStr& emsg)
  78. {
  79.     setInputBuffering(FALSE);
  80.     prevPage = FALSE;                // no previous page received
  81.     pageGood = FALSE;                // quality of received page
  82.  
  83.     return recvIdentification(
  84.     FCF_CSI|FCF_RCVR, lid, FCF_DIS|FCF_RCVR, modemDIS(),
  85.     conf.class1RecvIdentTimer, emsg);
  86. }
  87.  
  88. /*
  89.  * Transmit local identification and wait for the
  90.  * remote side to respond with their identification.
  91.  */
  92. fxBool
  93. Class1Modem::recvIdentification(u_int f1, const fxStr& id, u_int f2, u_int dics,
  94.     u_int timer, fxStr& emsg)
  95. {
  96.     u_int t1 = howmany(timer, 1000);        // in seconds
  97.     u_int trecovery = howmany(conf.class1TrainingRecovery, 1000);
  98.     time_t start = time(0);
  99.     HDLCFrame frame(conf.class1FrameOverhead);
  100.  
  101.     emsg = "No answer (T.30 T1 timeout)";
  102.     /*
  103.      * Transmit (NSF) (CSI) DIS frames when the receiving
  104.      * station or (NSC) (CIG) DTC when initiating a poll.
  105.      */
  106.     startTimeout(3000);
  107.     fxBool framesSent = sendFrame(f1, id, FALSE);
  108.     stopTimeout("sending id frame");
  109.     for (;;) {
  110.     if (framesSent) {
  111.         startTimeout(2550);
  112.         framesSent = sendFrame(f2, dics);
  113.         stopTimeout("sending DIS/DCS frame");
  114.     }
  115.     if (framesSent) {
  116.         /*
  117.          * Wait for a response to be received.
  118.          */
  119.         if (recvFrame(frame, conf.t4Timer)) {
  120.         do {
  121.             /*
  122.              * Verify a DCS command response and, if
  123.              * all is correct, receive phasing/training.
  124.              */
  125.             if (!recvDCSFrames(frame)) {
  126.             u_int fcf = frame.getFCF() &~ FCF_SNDR;
  127.             if (fcf == FCF_DCN)
  128.                 emsg = "RSPREC error/got DCN";
  129.             else            // XXX DTC/DIS not handled
  130.                 emsg = "RSPREC invalid response received";
  131.             break;
  132.             }
  133.             if (recvTraining()) {
  134.             emsg = "";
  135.             return (TRUE);
  136.             }
  137.             emsg = "Failure to train modems";
  138.             /*
  139.              * Reset the timeout to insure the T1 timer is
  140.              * used.  This is done because the adaptive answer
  141.              * strategy may setup a shorter timeout that's
  142.              * used to wait for the initial identification
  143.              * frame.  If we get here then we know the remote
  144.              * side is a fax machine and so we should wait
  145.              * the full T1 timeout, as specified by the protocol.
  146.              */
  147.             t1 = howmany(conf.t1Timer, 1000);
  148.         } while (recvFrame(frame, conf.t2Timer));
  149.         }
  150.     }
  151.     /*
  152.      * We failed to send our frames or failed to receive
  153.      * DCS from the other side.  First verify there is
  154.      * time to make another attempt...
  155.      */
  156.     if (time(0)+trecovery-start >= t1)
  157.         break;
  158.     /*
  159.      * Delay long enough to miss any training that the
  160.      * other side might have sent us.  Otherwise the
  161.      * caller will miss our retransmission since it'll
  162.      * be in the process of sending training.
  163.      */
  164.     pause(conf.class1TrainingRecovery);
  165.     /*
  166.      * Retransmit ident frames.
  167.      */
  168.         framesSent = transmitFrame(f1, id, FALSE);
  169.     }
  170.     return (FALSE);
  171. }
  172.  
  173. /*
  174.  * Receive DCS preceded by any optional frames.
  175.  */
  176. fxBool
  177. Class1Modem::recvDCSFrames(HDLCFrame& frame)
  178. {
  179.     fxStr tsi;
  180.     do {
  181.     switch (frame.getFCF()) {
  182.     case FCF_NSS|FCF_SNDR:
  183.         protoTrace("REMOTE NSS %#x", frame.getDataWord());
  184.         break;
  185.     case FCF_TSI|FCF_SNDR:
  186.         decodeTSI(tsi, frame);
  187.         recvCheckTSI(tsi);
  188.         break;
  189.     case FCF_DCS|FCF_SNDR:
  190.         processDCSFrame(frame);
  191.         break;
  192.     }
  193.     } while (frame.moreFrames() && recvFrame(frame, conf.t4Timer));
  194.     return (frame.isOK() && frame.getFCF() == (FCF_DCS|FCF_SNDR));
  195. }
  196.  
  197. /*
  198.  * Receive training and analyze TCF.
  199.  */
  200. fxBool
  201. Class1Modem::recvTraining()
  202. {
  203.     protoTrace("RECV training at %s %s",
  204.     modulationNames[curcap->mod],
  205.     Class2Params::bitRateNames[curcap->br]);
  206.     HDLCFrame buf(conf.class1FrameOverhead);
  207.     fxBool ok = recvTCF(curcap->value, buf, frameRev, 4500);
  208.     if (ok) {                    // check TCF data
  209.     u_int n = buf.getLength();
  210.     u_int nonzero = 0;
  211.     u_int zerorun = 0;
  212.     u_int i = 0;
  213.     /*
  214.      * Determine number of non-zero bytes and
  215.      * the longest zero-fill run in the data.
  216.      */
  217.     while (i < n) {
  218.         u_int j;
  219.         for (; i < n && buf[i] != 0; i++)
  220.         nonzero++;
  221.         for (j = i; j < n && buf[j] == 0; j++)
  222.         ;
  223.         if (j-i > zerorun)
  224.         zerorun = j-i;
  225.         i = j;
  226.     }
  227.     /*
  228.      * Our criteria for accepting is that there must be
  229.      * no more than 10% non-zero (bad) data and the longest
  230.      * zero-run must be at least at least 2/3'rds of the
  231.      * expected TCF duration.  This is a hack, but seems
  232.      * to work well enough.  What would be better is to
  233.      * anaylze the bit error distribution and decide whether
  234.      * or not we would receive page data with <N% error,
  235.      * where N is probably ~5.  If we had access to the
  236.      * modem hardware, the best thing that we could probably
  237.      * do is read the Eye Quality register (or similar)
  238.      * and derive an indicator of the real S/N ratio.
  239.      */
  240.     u_int minrun = params.transferSize((2*TCF_DURATION)/3);
  241.     nonzero = (100*nonzero) / (n == 0 ? 1 : n);
  242.     protoTrace("RECV: TCF %u bytes, %u%% non-zero, %u zero-run",
  243.         n, nonzero, zerorun);
  244.     if (nonzero > 10 || zerorun < minrun)
  245.         ok = FALSE;
  246.     (void) waitFor(AT_NOCARRIER);    // wait for message carrier to drop
  247.     }
  248.     /*
  249.      * Send training response; we follow the spec
  250.      * by delaying 75ms before switching carriers.
  251.      */
  252.     pause(conf.class1TCFResponseDelay);
  253.     if (ok) {
  254.     transmitFrame(FCF_CFR|FCF_RCVR);
  255.     protoTrace("TRAINING succeeded");
  256.     } else {
  257.     transmitFrame(FCF_FTT|FCF_RCVR);
  258.     protoTrace("TRAINING failed");
  259.     }
  260.     return (ok);
  261. }
  262.  
  263. /*
  264.  * Process a received DCS frame.
  265.  */
  266. void
  267. Class1Modem::processDCSFrame(const HDLCFrame& frame)
  268. {
  269.     u_int dcs = frame.getDIS();            // NB: really DCS
  270.     params.setFromDCS(dcs, frame.getXINFO());
  271.     setDataTimeout(60, params.br);
  272.     curcap = findSRCapability(dcs&DCS_SIGRATE, recvCaps);
  273.     recvDCS(params);                // pass to server
  274. }
  275.  
  276. const u_int Class1Modem::modemPPMCodes[8] = {
  277.     0,            // 0
  278.     PPM_EOM,        // FCF_EOM+FCF_PRI_EOM
  279.     PPM_MPS,        // FCF_MPS+FCF_PRI_MPS
  280.     0,            // 3
  281.     PPM_EOP,        // FCF_EOP+FCF_PRI_EOP
  282.     0,            // 5
  283.     0,            // 6
  284.     0,            // 7
  285. };
  286.  
  287. /*
  288.  * Receive a page of data.
  289.  *
  290.  * This routine is called after receiving training or after
  291.  * sending a post-page response in a multi-page document.
  292.  */
  293. fxBool
  294. Class1Modem::recvPage(TIFF* tif, int& ppm, fxStr& emsg)
  295. {
  296.     fxBool messageReceived = FALSE;        // message carrier received
  297.     do {
  298.     u_int timer = conf.t2Timer;
  299.     if (!messageReceived) {
  300.         /*
  301.          * Look for message carrier and receive Phase C data.
  302.          */
  303.         setInputBuffering(TRUE);
  304.         if (flowControl == FLOW_XONXOFF)
  305.         (void) setXONXOFF(FLOW_NONE, FLOW_XONXOFF, ACT_FLUSH);
  306.         /*
  307.          * Set high speed carrier & start receive.  If the
  308.          * negotiated modulation technique includes short
  309.          * training, then we use it here (it's used for all
  310.          * high speed carrier traffic other than the TCF).
  311.          */
  312.         int speed = curcap[HasShortTraining(curcap)].value;
  313.         (void) class1Cmd("RM", speed, AT_NOTHING);
  314.         ATResponse rmResponse = atResponse(rbuf, conf.t2Timer);
  315.         if (rmResponse == AT_CONNECT) {
  316.         /*
  317.          * The message carrier was recognized;
  318.          * receive the Phase C data.
  319.          */
  320.         protoTrace("RECV: begin page");
  321.         recvSetupPage(tif, 0, FILLORDER_LSB2MSB);
  322.         pageGood = recvPhaseC(tif, emsg);
  323.         protoTrace("RECV: end page");
  324.         if (!wasTimeout()) {
  325.             /*
  326.              * The data was received correctly, wait
  327.              * for the modem to signal carrier drop.
  328.              */
  329.             messageReceived = waitFor(AT_NOCARRIER, 2*1000);
  330.             if (messageReceived)
  331.             prevPage = TRUE;
  332.             timer = conf.t1Timer;        // wait longer for PPM
  333.         }
  334.         }
  335.         if (flowControl == FLOW_XONXOFF)
  336.         (void) setXONXOFF(FLOW_NONE, FLOW_NONE, ACT_DRAIN);
  337.         setInputBuffering(FALSE);
  338.         if (!messageReceived && rmResponse != AT_FCERROR) {
  339.         /*
  340.          * One of many things may have happened:
  341.          * o if we lost carrier, then some modems will return
  342.          *   AT_NOCARRIER or AT_EMPTYLINE in response to the
  343.          *   AT+FRM request.
  344.          * o otherwise, there may have been a timeout receiving
  345.          *   the message data, or there was a timeout waiting
  346.          *   for the carrier to drop.  Anything unexpected causes
  347.          *   us abort the receive to avoid looping.
  348.          * The only case that we don't abort on is that we found
  349.          * the wrong carrier, which means that there is an HDLC
  350.          * frame waiting for us--in which case it should get
  351.          * picked up below.
  352.          */
  353.         break;
  354.         }
  355.     }
  356.     /*
  357.      * Do command received logic.
  358.      */
  359.     HDLCFrame frame(conf.class1FrameOverhead);
  360.     if (recvFrame(frame, timer)) {
  361.         u_int fcf = frame.getFCF();
  362.         switch (fcf) {
  363.         case FCF_DTC:            // XXX no support
  364.         case FCF_DIS:            // XXX no support
  365.         protoTrace("RECV DIS/DTC");
  366.         emsg = "Can not continue after DIS/DTC";
  367.         return (FALSE);
  368.         case FCF_NSS|FCF_SNDR:
  369.         case FCF_TSI|FCF_SNDR:
  370.         case FCF_DCS|FCF_SNDR:
  371.         if (recvDCSFrames(frame))
  372.             (void) recvTraining();
  373.         messageReceived = FALSE;    // look for message carrier
  374.         break;
  375.         case FCF_MPS|FCF_SNDR:        // MPS
  376.         case FCF_EOM|FCF_SNDR:        // EOM
  377.         case FCF_EOP|FCF_SNDR:        // EOP
  378.         case FCF_PRI_MPS|FCF_SNDR:        // PRI-MPS
  379.         case FCF_PRI_EOM|FCF_SNDR:        // PRI-EOM
  380.         case FCF_PRI_EOP|FCF_SNDR:        // PRI-EOP
  381.         tracePPM("RECV recv", fcf);
  382.         if (!prevPage) {
  383.             /*
  384.              * Post page message, but no previous page
  385.              * was received--this violates the protocol.
  386.              */
  387.             emsg = "COMREC invalid response received";
  388.             return (FALSE);
  389.         }
  390.         /*
  391.          * [Re]transmit post page response.
  392.          */
  393.         if (pageGood) {
  394.             (void) transmitFrame(FCF_MCF|FCF_RCVR);
  395.             tracePPR("RECV send", FCF_MCF);
  396.             /*
  397.              * If post page message confirms the page
  398.              * that we just received, write it to disk.
  399.              */
  400.             if (messageReceived) {
  401.             TIFFWriteDirectory(tif);
  402.             countPage();
  403.             ppm = modemPPMCodes[fcf&7];
  404.             return (TRUE);
  405.             }
  406.         } else {
  407.             /*
  408.              * Page not received, or unacceptable; tell
  409.              * other side to retransmit after retrain.
  410.              */
  411.             (void) transmitFrame(FCF_RTN|FCF_RCVR);
  412.             tracePPR("RECV send", FCF_RTN);
  413.             /*
  414.              * Reset the TIFF-related state so that subsequent
  415.              * writes will overwrite the previous data.
  416.              */
  417.             recvResetPage(tif);
  418.             messageReceived = TRUE;    // expect DCS next
  419.         }
  420.         break;
  421.         case FCF_DCN|FCF_SNDR:        // DCN
  422.         tracePPM("RECV recv", fcf);
  423.         emsg = "COMREC received DCN";
  424.         return (FALSE);
  425.         default:
  426.         emsg = "COMREC invalid response received";
  427.         return (FALSE);
  428.         }
  429.     }
  430.     } while (!wasTimeout() && lastResponse != AT_EMPTYLINE);
  431.     emsg = "T.30 T2 timeout, expected page not received";
  432.     return (FALSE);
  433. }
  434.  
  435. /*
  436.  * Receive Phase C data.
  437.  */
  438. fxBool
  439. Class1Modem::recvPhaseC(TIFF* tif, fxStr& emsg)
  440. {
  441.     startPageRecv();
  442.  
  443.     fxBool prematureEOF = FALSE;
  444.     u_char buf[16*1024];
  445.     int n = 0;
  446.     for (;;) {
  447.     int b = getModemDataChar();
  448.     if (b == EOF) {
  449.         protoTrace("RECV: premature EOF");
  450.         prematureEOF = TRUE;
  451.         break;
  452.     }
  453.     if (b == DLE) {
  454.         b = getModemDataChar();
  455.         if (b == EOF || b == ETX) {
  456.         if (b == EOF) {
  457.             prematureEOF = TRUE;
  458.             emsg = "Premature EOF";
  459.             protoTrace("RECV: %s", (char*) emsg);
  460.         }
  461.         break;
  462.         }
  463.         if (b != DLE) {
  464.         if (n == sizeof (buf))
  465.             recvData(tif, buf, sizeof (buf)), n = 0;
  466.         buf[n++] = DLE;
  467.         }
  468.     }
  469.     if (n == sizeof (buf))
  470.         recvData(tif, buf, sizeof (buf)), n = 0;
  471.     buf[n++] = b;
  472.     }
  473.     if (n > 0)
  474.     recvData(tif, buf, n);
  475.     endPageRecv(params);
  476.     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, getRecvEOLCount());
  477. #ifdef notdef
  478.     TIFFSetField(tif, TIFFTAG_CLEANFAXDATA, blc ?
  479.     CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
  480.     if (blc) {
  481.     TIFFSetField(tif, TIFFTAG_BADFAXLINES, (u_long) blc);
  482.     TIFFSetField(tif, TIFFTAG_CONSECUTIVEBADFAXLINES, cblc);
  483.     }
  484. #endif
  485.     if (prematureEOF) {
  486.     emsg = "Missing EOL after 5 seconds";
  487.     char c = CAN;            // anything other than DC1/DC3
  488.     putModem(&c, 1, 1);
  489.     }
  490.     return (TRUE);
  491. }
  492.  
  493. /*
  494.  * Write received data to the current file.
  495.  */
  496. void
  497. Class1Modem::recvData(TIFF* tif, u_char* bp, int n)
  498. {
  499.     /*
  500.      * Always put data out to the file in LSB2MSB bit order.
  501.      * We do this because some TIFF readers (mostly on the PC)
  502.      * don't understand MSB2LSB and/or the FillOrder tag.
  503.      */
  504.     if (conf.recvFillOrder != FILLORDER_LSB2MSB)
  505.     TIFFReverseBits(bp, n);
  506.     FaxModem::recvPageData(tif, bp, n);
  507. }
  508.  
  509. /*
  510.  * Complete a receive session.
  511.  */
  512. fxBool
  513. Class1Modem::recvEnd(fxStr&)
  514. {
  515.     u_int t1 = howmany(conf.t1Timer, 1000);    // T1 timer in seconds
  516.     time_t start = time(0);
  517.     /*
  518.      * Wait for DCN and retransmit ack of EOP if needed.
  519.      */
  520.     HDLCFrame frame(conf.class1FrameOverhead);
  521.     do {
  522.     if (recvFrame(frame, conf.t2Timer)) {
  523.         switch (frame.getFCF()) {
  524.         case FCF_EOP|FCF_SNDR:
  525.         (void) transmitFrame(FCF_MCF|FCF_RCVR);
  526.         tracePPM("RECV recv", FCF_EOP);
  527.         tracePPR("RECV send", FCF_MCF);
  528.         break;
  529.         case FCF_DCN|FCF_SNDR:
  530.         break;
  531.         default:
  532.         transmitFrame(FCF_DCN|FCF_RCVR);
  533.         break;
  534.         }
  535.     } else if (!wasTimeout() && lastResponse != AT_FCERROR) {
  536.         /*
  537.          * Beware of unexpected responses from the modem.  If
  538.          * we lose carrier, then we can loop here if we accept
  539.          * null responses, or the like.
  540.          */
  541.         break;
  542.     }
  543.     } while (time(0)-start < t1 &&
  544.     (!frame.isOK() || frame.getFCF() == (FCF_EOP|FCF_SNDR)));
  545.     setInputBuffering(TRUE);
  546.     return (TRUE);
  547. }
  548.